package com.zhugang.week03;

import java.util.Stack;

/**
 * @program algorithms
 * @description: stackCalculateBase2
 * @author: chanzhugang
 * @create: 2022/06/08 21:31
 */
public class StackCalculateBase2 {

    public static void main(String[] args) {
        StackCalculateBase2 stackCalculateBase2 = new StackCalculateBase2();
        String s = "2*(5+5*2)/3+(6/2+8)";
        int res = stackCalculateBase2.calculate(s);
        System.out.println(res);
    }

    /**
     * 772. 基本计算器III, 有括号处理
     *
     * @param s
     * @return
     */
    public int calculate(String s) {
        /**
         * 定义两个栈，一个数字栈，一个字符栈
         * 遇到字符压入字符栈，如果当前字符比栈顶字符优先级高，压入字符栈，否则取出字符栈栈顶元素和数字栈栈顶元素计算，结果压入数字栈
         */
        Stack<Integer> numsStack = new Stack<>();
        Stack<Character> opsStack = new Stack<>();
        int i = 0;
        int n = s.length();
        while (i < n) {
            char c = s.charAt(i);
            if (c == ' ') {
                i++;
            } else if (isDigit(c)) {
                int number = 0;
                while (i < n && isDigit(s.charAt(i))) {
                    // 多个数字字符转数字
                    number = number * 10 + (s.charAt(i) - '0');
                    i++;
                }
                numsStack.push(number);
            } else if (c == '(') {
                opsStack.push(c);
                i++;
            } else if (c == ')') {
                while (!opsStack.isEmpty() && opsStack.peek() != '(') {
                    fetchAndCal(numsStack, opsStack);
                }
                // 弹出')'
                opsStack.pop();
                i++;
            } else {
                if (opsStack.isEmpty() || prior(c, opsStack.peek())) {
                    opsStack.push(c);
                } else {
                    while (!opsStack.isEmpty() && !prior(c, opsStack.peek())) {
                        fetchAndCal(numsStack, opsStack);
                    }
                    opsStack.push(c);
                }
                i++;
            }
        }
        while (!opsStack.isEmpty()) {
            fetchAndCal(numsStack, opsStack);
        }
        return numsStack.pop();
    }

    private void fetchAndCal(Stack<Integer> numsStack, Stack<Character> opsStack) {
        Integer num2 = numsStack.pop();
        Integer num1 = numsStack.pop();
        char ops = opsStack.pop();
        int res = cal(ops, num1, num2);
        numsStack.push(res);
    }

    private int cal(char ops, Integer num1, Integer num2) {
        switch (ops) {
            case '+':
                return num1 + num2;
            case '-':
                return num1 - num2;
            case '*':
                return num1 * num2;
            case '/':
                return num1 / num2;
        }
        return -1;
    }

    private boolean prior(char a, char b) {
        if ((a == '*' || a == '/') && (b == '+' || b == '-')) {
            return true;
        }
        return b == '(';

    }

    private boolean isDigit(char c) {
        return c >= '0' && c <= '9';
    }
}